/*
 * WindowController.java
 *
 * Created on November 4, 2006, 7:55 AM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package edu.umn.cs5115.scheduler.framework;

import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.ShellEvent;
import org.eclipse.swt.events.ShellListener;
import org.eclipse.swt.widgets.Shell;

/**
 * A window controller manages a single window.  It is contained by a document.
 * When the window is closed, it asks the document before closing and may close
 * the entire document as a result.  You can use this class as-is or subclass it
 * to add functionality for a specific window.
 * @author grant
 */
public class WindowController implements ShellListener
{
    private Document document;
    private Shell window;
    private boolean shouldCloseDocument;
    private DisposeListener windowDisposeListener;
    
    // Listens for changes in the document's display name to update the window's
    // title bar.
    private KeyValueObserver documentNameListener = new KeyValueAdapter()
    {
        public void valueChanged(KeyValueCoding object, String key)
        {
            Shell window = getWindow();
            if (window != null)
                window.setText(getWindowTitle());
        }
    };
    
    /** 
     * Creates a new instance of WindowController.  If you create a subclass,
     * you should normally define a constructor that creates your window in the
     * default constructor and then set it as the WindowController's window 
     * using setWindow(Shell).
     * @param document The document that this WindowController's window will 
     * display data for.
     * @see #setWindow(Shell)
     */
    public WindowController(Document document)
    {
        setDocument(document);
    }
    
    /**
     * Creates a new instance of WindowController to manage the specified shell.
     * @param document The document that this WindowController's window will 
     * display data for.
     * @param window The window this window controller is for.
     */
    public WindowController(Document document, Shell window)
    {
        setDocument(document);
        setWindow(window);
    }
    
    /**
     * Called when the window is being disposed of.  Subclasses should break any 
     * bindings left open to the interface at this point so that they will not
     * try to modify the window any longer.
     * Remember to call super's implementation if you override this.
     */
    protected void disposing()
    {
        document.removeListener(documentNameListener, Document.DISPLAY_NAME);
    }
    
    /** 
     * Set the document this window controller is associated with.
     * @param document The new document to associate with.
     */
    private void setDocument(Document document)
    {
        this.document = document;
        document.addWindowController(this);
        document.addListener(documentNameListener, Document.DISPLAY_NAME);
    }

    /** 
     * Get the document that this window controller is associated with.
     * @return The document for this window controller.
     */
    public Document getDocument()
    {
        return document;
    }

    /**
     * Get the window displayed by this window controller.
     * @return The window associated with the WindowController.
     */
    public Shell getWindow()
    {
        return window;
    }
    
    /**
     * Sets the window controlled by this WindowController.
     * @param window The new window to be controlled by the window controller.
     */
    public void setWindow(Shell window)
    {
        if (this.window != null)
        {
            this.window.removeShellListener(this);
            this.window.removeDisposeListener(windowDisposeListener);
        }
        if (windowDisposeListener == null)
        {
            windowDisposeListener = new DisposeListener()
            {
                public void widgetDisposed(DisposeEvent e)
                {
                    WindowController.this.disposing();
                }
            };
        }
        window.addShellListener(this);
        window.addDisposeListener(windowDisposeListener);
        DocumentController.getSharedDocumentController().getMainMenu().createMenuBar(window, document);
        window.setText(getWindowTitle());
        this.window = window;
    }
    
    /**
     * Get the text for the window's title bar.  You should override this to
     * customize that text.
     * @return The text that will be used for the title bar.
     */
    public String getWindowTitle()
    {
        return document.getDisplayName();
    }
    
    /**
     * Show the window associated with this document controller, displaying it
     * and bringing it to the front if necessary.
     */
    public void showWindow()
    {
        if (window != null)
            window.open();
    }

    /**
     * Tests whether or not closing the window associated with this 
     * WindowController should close the entire document.
     * @return True if closing this window should be interpreted as closing the
     * entire document, regardless of how many other windows may be open.  False
     * if closing the window should only close the document if this is the last
     * window associated with that document.
     * @see #setShouldCloseDocument(boolean)
     */
    public boolean getShouldCloseDocument()
    {
        return shouldCloseDocument;
    }

    /**
     * Sets whether or not closing this window should close the entire document,
     * regardless of how many other windows may be open.
     * @param shouldCloseDocument True if closing this window should close the
     * document and all other associated windows.  False if the document should
     * only be closed if this is the last window in the document open when it
     * is closed.
     * @see #getShouldCloseDocument()
     */
    public void setShouldCloseDocument(boolean shouldCloseDocument)
    {
        this.shouldCloseDocument = shouldCloseDocument;
    }

    /** Notice when the window is activated so we can set the active document. */
    public void shellActivated(ShellEvent e)
    {
        DocumentController.getSharedDocumentController().setActiveDocument(getDocument());
    }
    /** Required by ShellListener interface. */
    public void shellDeactivated(ShellEvent e) {}
    /** Required by ShellListener interface. */
    public void shellDeiconified(ShellEvent e) {}
    /** Required by ShellListener interface. */
    public void shellIconified(ShellEvent e) {}
    /** Notice when the window is closing to stop it if necessary. */
    public void shellClosed(ShellEvent e)
    {
        if (!document.shouldCloseWindowController(this))
            e.doit = false;
        else
            document.removeWindowController(this);
    }
}
